package com.desaysv.svhttp;

import android.util.Log;

import com.desaysv.svhttp.anno.Body;
import com.desaysv.svhttp.anno.DELETE;
import com.desaysv.svhttp.anno.Entity;
import com.desaysv.svhttp.anno.GET;
import com.desaysv.svhttp.anno.Header;
import com.desaysv.svhttp.anno.POST;
import com.desaysv.svhttp.anno.PUT;
import com.desaysv.svhttp.anno.Param;
import com.desaysv.svhttp.anno.Path;
import com.desaysv.svhttp.anno.SavePath;
import com.desaysv.svhttp.anno.Url;
import com.desaysv.svhttp.callback.IBaseCallBack;
import com.desaysv.svhttp.coder.IResponseDecoder;
import com.desaysv.svhttp.handler.IHandler;
import com.desaysv.svhttp.handler.impl.HttpHandler;
import com.desaysv.svhttp.handler.type.HttpType;
import com.desaysv.svhttp.interceptor.IInterceptor;
import com.desaysv.svhttp.param.HttpParams;
import com.google.gson.Gson;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;


/**
 * @author linzi
 * @version 1.0
 * @date 2022-7-19
 * @since 2022-7-19
 */
public final class SVHttp {
    /**
     * 代理池
     */
//    private final ConcurrentHashMap<Class, Object> PROXY_POOL = new ConcurrentHashMap<>();
    private final LinkedHashMap<String, Object> mProxyPool = new LinkedHashMap<>();
    /**
     * 日志TAG
     */
    private static final String TAG = "[SVHttp]";
    /**
     * 网络代理类
     */
    private Class<? extends IHandler> mDefaultCla = HttpHandler.class;

    /**
     * 构造函数
     *
     * @author uidq5208
     * @date 2022-12-13 13:55
     */
    private SVHttp() {

    }

    public static class Builder {
        private SVHttp svHttp;

        public Builder() {
            Log.i(TAG, "Builder: ");
            svHttp = new SVHttp();
        }

        public <T extends IHandler> Builder setHttpProxy(Class<T> defaultCla) {
            svHttp.setHttpProxy(defaultCla);
            return this;
        }

        public Builder setBaseUrl(String url) {
            svHttp.setBaseUrl(url);
            return this;
        }

        public Builder setResponseCoder(IResponseDecoder decoder) {
            svHttp.setResponseCoder(decoder);
            return this;
        }

        public Builder setInterceptor(IInterceptor cla) {
            svHttp.setInterceptor(cla);
            return this;
        }

        public SVHttp build() {
            return svHttp;
        }
    }

    /**
     * @param <T>        代理类
     * @param defaultCla
     * @return
     * @author linzi
     * @date 2022-7-20 15:46
     * @context 网络操作代理
     */
    private  <T extends IHandler> void setHttpProxy(Class<T> defaultCla) {
        if (defaultCla == null) {
            mDefaultCla = HttpHandler.class;
            return;
        }
        this.mDefaultCla = defaultCla;
    }

    /**
     * @param url 请求的基础路径
     * @return SVHttp
     * @author linzi
     * @date 2022-7-20 15:43
     * @context 设置基础地址
     */
    public SVHttp setBaseUrl(String url) {
        IHandler httpHandler = SVHttpProxy.getFactory().getProxy(mDefaultCla);
        httpHandler.baseUrl(url);
        return this;
    }

    /**
     * @param decoder 响应解码器
     * @return SVHttp
     * @author linzi
     * @date 2022-7-20 15:44
     * @context 设置响应的解码器
     */
    private void setResponseCoder(IResponseDecoder decoder) {
        IHandler httpHandler = SVHttpProxy.getFactory().getProxy(mDefaultCla);
        httpHandler.responseDecoder(decoder);
    }

    /**
     * @param cla 拦截器
     * @return SVHttp
     * @author linzi
     * @date 2022-7-20 15:44
     * @context 设置拦截器
     */
    private void setInterceptor(IInterceptor cla) {
        IHandler httpHandler = SVHttpProxy.getFactory().getProxy(mDefaultCla);
        httpHandler.setInterceptor(cla);
    }

    /**
     * @param <T> 请求服务
     * @param t   请求服务
     * @return 请求服务实例对象
     * @author linzi
     * @date 2022-7-20 15:44
     * @context 创建服务实例
     */
    public <T> T create(Class<T> t) {
        if (!t.isInterface()) {
            throw new RuntimeException("Service must be interface");
        }
        Object temp = mProxyPool.get(t.getName());
        if (temp == null) {
            synchronized (SVHttp.class) {
                temp = mProxyPool.get(t.getName());
                if (temp == null) {
                    try {
                        temp = Proxy.newProxyInstance(t.getClassLoader(), new Class<?>[]{t}, (Object pxy, Method method, Object[] args) -> {
                            return action(this, method, args);
                        });
                        mProxyPool.put(t.getName(), temp);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return (T) temp;
    }

    /**
     * @param object 代理对象
     * @param method 代理函数
     * @param args   请求参数
     * @return 返回对象
     * @throws IllegalAccessException    异常信息
     * @throws InvocationTargetException 异常信息
     * @author linzi
     * @date 2022-7-20 15:44
     * @context 请求服务网络操作代理
     */
    private Object action(Object object, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        IHandler httpHandler = SVHttpProxy.getFactory().getProxy(mDefaultCla);
        HttpParams params = readParams(method, args);
        if (BuildConfig.DEBUG) {
            Log.d(TAG, params.getParams());
        }
        IBaseCallBack callBack = readBack(args);
        HttpType requestType = null;
        String requestPath = "";
        if (method.isAnnotationPresent(GET.class)) {
            GET annoGet = method.getAnnotation(GET.class);
            assert annoGet != null;
            requestPath = annoGet.path();
            requestType = HttpType.GET;
        } else if (method.isAnnotationPresent(POST.class)) {
            POST annoPost = method.getAnnotation(POST.class);
            if (method.isAnnotationPresent(Body.class)) {
                Body annoBody = method.getAnnotation(Body.class);
                params.setContentType(annoBody.value());
            }
            requestPath = annoPost.path();
            requestType = HttpType.POST;
        } else if (method.isAnnotationPresent(DELETE.class)) {
            DELETE annoPost = method.getAnnotation(DELETE.class);
            if (method.isAnnotationPresent(Body.class)) {
                Body annoBody = method.getAnnotation(Body.class);
                params.setContentType(annoBody.value());
            }
            requestPath = annoPost.path();
            requestType = HttpType.DELETE;
        } else if (method.isAnnotationPresent(PUT.class)) {
            PUT annoPost = method.getAnnotation(PUT.class);
            if (method.isAnnotationPresent(Body.class)) {
                Body annoBody = method.getAnnotation(Body.class);
                params.setContentType(annoBody.value());
            }
            requestPath = annoPost.path();
            requestType = HttpType.PUT;
        }
        httpHandler.request(requestType, requestPath, params, callBack);
        //自行代理业务
//        return method.invoke(object,args);
        return null;
    }

    /**
     * @param method 方法函数
     * @param args   参数集合
     * @return HttpParams
     * @author linzi
     * @date 2022-7-20 15:44
     * @context 读取参数
     */
    private HttpParams readParams(Method method, Object[] args) {
        HttpParams params = null;
        for (Object arg : args) {
            if (arg.getClass().equals(HttpParams.class)) {
                params = (HttpParams) arg;
                break;
            }
        }
        if (params != null) {
            return params;
        }
        params = new HttpParams();
        Annotation[][] annotations = method.getParameterAnnotations();
        for (int i = 0; i < args.length; i++) {
            Annotation[] annos = annotations[i];
            for (Annotation anno : annos) {
                if (anno.annotationType().equals(Entity.class)) {
                    if (args[i] instanceof String) {
                        params.setJson((String) args[i]);
                    } else {
                        try {
                            String json = new Gson().toJson(args[i]);
                            params.setJson(json);
                        } catch (Exception e) {
                            Log.e(TAG, "readParams: ", e);
                        }
                    }
                }
                //获取参数注解
                if (anno.annotationType().equals(Param.class)) {
                    params.addParams(((Param) anno).key(), args[i]);
                }
                //获取自定义请求头
                if (anno.annotationType().equals(Header.class)) {
                    params.addHeader(((Header) anno).key(), (String) args[i]);
                }
                //获取下载路径
                if (anno.annotationType().equals(SavePath.class)) {
                    if (args[i] instanceof String) {
                        params.setSavePath((String) args[i]);
                    }
                }
                //获取自定义请求地址
                if (anno.annotationType().equals(Url.class)) {
                    if (args[i] instanceof String) {
                        params.setSingleUrl((String) args[i]);
                    }
                }
                //获取自定义路径请求地址
                if (anno.annotationType().equals(Path.class)) {
                    if (args[i] instanceof String) {
                        params.addPathParams(((Path) anno).key(), args[i]);
                    } else {
                        params.addPathParams(((Path) anno).key(), args[i].toString());
                    }
                }
            }
        }
        return params;
    }

    /**
     * @param args 参数集合
     * @return IBaseCallBack 对象
     * @author linzi
     * @date 2022-7-20 15:45
     * @context 获取回调
     */
    private IBaseCallBack readBack(Object[] args) {
        for (Object arg : args) {
            if (arg instanceof IBaseCallBack) {
                return (IBaseCallBack) arg;
            }
        }
        return null;
    }

    /**
     * @param t   泛型
     * @param <T> 类型
     * @return 响应结果
     */
    public <T> boolean checkInit(Class<T> t) {
        return mProxyPool.get(t.getName()) != null;
    }
}
